﻿using Microsoft.AspNetCore.Mvc.Formatters;
using Microsoft.Net.Http.Headers;
using System.Text;
using WebApi.Models;

namespace WebApi.CustomFormatter;

public class VCardInputFormatter : TextInputFormatter
{
    public VCardInputFormatter()
    {
        SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("text/vcard"));
        SupportedEncodings.Add(Encoding.UTF8);
        SupportedEncodings.Add(Encoding.Unicode);
    }
    protected override bool CanReadType(Type type)
    {
        // 只支持 Contact 类型
        return typeof(Contact).IsAssignableFrom(type);
    }

    private async static Task<string> ReadLineAsync(string v, StreamReader reader, InputFormatterContext context, ILogger<VCardInputFormatter> logger)
    {
        var line = await reader.ReadLineAsync();
        if (line == null || !line.StartsWith(v))
        {
            var errMsg = $"Looked for {v} and go {line}";
            logger.LogError(errMsg);
            context.ModelState.TryAddModelError(context.ModelName, errMsg);
            throw new Exception("VCard is not well formatted");
        }
        return line;
    }

    public override async Task<InputFormatterResult> ReadRequestBodyAsync(InputFormatterContext context, Encoding encoding)
    {
        var httpContext = context.HttpContext;
        var serviceProvider = httpContext.RequestServices;
        var logger = serviceProvider.GetRequiredService<ILogger<VCardInputFormatter>>();

        using var reader = new StreamReader(httpContext.Request.Body, encoding);
        string? nameLine = null;
        try
        {
            await ReadLineAsync("BEGIN:VCARD", reader, context, logger);
            await ReadLineAsync("VERSION", reader, context, logger);
            nameLine = await ReadLineAsync("N", reader, context, logger);
            var split = nameLine.Split(';');
            await ReadLineAsync("FN", reader, context, logger);
            var contact = new Contact(firstName: split[1], split[0].Substring(2));
            await ReadLineAsync("END:VCARD", reader, context, logger);

            logger.LogInformation("VCard for {Contact} generated", contact.FullName);

            return await InputFormatterResult.SuccessAsync(contact);
        }
        catch (Exception ex)
        {
            logger.LogError(ex, "Error reading VCard");
            return await InputFormatterResult.FailureAsync();
        }
    }
}
